package model.algorithms.rounding;

import java.util.LinkedHashMap;

import model.components.networks.sdn.SdnNetwork;
import model.components.networks.virtual.VirtualNetwork;
import model.components.nodes.node.sdn.SdnNode;
import model.components.nodes.node.virtual.VirtualNode;

public class Randomized2 extends RoundingAlgorithm
{
	public Randomized2( String name ){ super( name ); }
	
	@Override
	public LinkedHashMap< VirtualNode, SdnNode > run( VirtualNetwork virtualNetwork, SdnNetwork physicalNetwork, double x[][][], double f[][][] )
	{
		LinkedHashMap< VirtualNode, SdnNode > mappingNodes = new LinkedHashMap< VirtualNode, SdnNode >();
		
		boolean nodesSubSel[] = new boolean[ physicalNetwork.getNodes().size() ];
		double sumFlows[] = new double[ physicalNetwork.getNodes().size() ];
		boolean control = true;
		
		for( VirtualNode nodeRequest: virtualNetwork.getVirtualNodes() )
		{
			int iNodeReq = nodeRequest.getNumber();
			double sumFlowsTotal = 0;
			
			for( SdnNode nodeSubstrate: physicalNetwork.getSdnNodes() )
			{
				int iNodeSub = nodeSubstrate.getNumber();
				int iNodeAug = iNodeSub + virtualNetwork.getNodes().size();
				
				if( nodeRequest.getType().equalsIgnoreCase( nodeSubstrate.getType() ) && !nodesSubSel[ iNodeSub ] )
				{
					for( int i = 0; i < virtualNetwork.getVirtualLinks().size(); i++ )
						sumFlows[ iNodeSub ] += x[ i ][ iNodeReq ][ iNodeAug ] * ( f[ i ][ iNodeReq ][ iNodeAug ] + f[ i ][ iNodeAug ][ iNodeReq ] );
				
					sumFlowsTotal += sumFlows[ iNodeSub ];
				}
			}
			
			double averageSumFlows = 0;
			double random = Math.random();
			SdnNode nodeSubSel = null;
			
			for( SdnNode nodeSubstrate: physicalNetwork.getSdnNodes() )
				if( nodeRequest.getType().equalsIgnoreCase( nodeSubstrate.getType() ) && !nodesSubSel[ nodeSubstrate.getNumber() ] )
				{
					sumFlows[ nodeSubstrate.getNumber() ] /= sumFlowsTotal;
					averageSumFlows += sumFlows[ nodeSubstrate.getNumber() ];
				
					if( averageSumFlows > random )
					{
						nodesSubSel[ nodeSubstrate.getNumber() ] = true;
						nodeSubSel = nodeSubstrate;
						mappingNodes.put( nodeRequest, nodeSubSel );
						break;
					}
				}
			
			if( nodeSubSel == null )
				control = false;
		}
		
		if( control == false )
			mappingNodes = null;
		
		return mappingNodes;
	}
	
}
